package com.shanhy.example.agent;

import net.bytebuddy.implementation.bind.annotation.AllArguments;
import net.bytebuddy.implementation.bind.annotation.Origin;
import net.bytebuddy.implementation.bind.annotation.RuntimeType;
import net.bytebuddy.implementation.bind.annotation.SuperCall;
import net.bytebuddy.implementation.bind.annotation.This;

import java.lang.reflect.Method;
import java.util.concurrent.Callable;

/**
 * 监听拦截方法
 *
 * @author 单红宇
 * @date 2024-03-07 15:25:50
 */
public class MonitorMethod {

    /**
     * 方法拦截处理器。
     * 方法使用注解 @RuntimeType 告诉 Byte Buddy 不要进行严格的参数类型检测，
     * 在参数匹配失败时，尝试使用类型转换方式（runtime type casting）进行类型转换，匹配相应方法
     *
     * @param obj      使用 @This 注入被拦截的目标对象
     * @param method   使用 @Origin 注入目标方法对应的 Method 对象
     * @param callable 我们要在方法中调用目标方法的话，需要通过 @SuperCall 注入
     * @param args     使用 @AllArguments 注入目标方法的全部参数
     * @return 方法执行结果
     * @throws Exception Exception
     */
    @RuntimeType
    public static Object intercept(@This Object obj, @Origin Method method, @SuperCall Callable<?> callable,
                                   @AllArguments Object[] args) throws Exception {
        long start = System.currentTimeMillis();
        Object resObj = null;
        try {
            resObj = callable.call();
            return resObj;
        } finally {
            System.out.println("所属类名：" + method.getDeclaringClass());
            System.out.println("方法名称：" + method.getName());
            System.out.println("入参个数：" + method.getParameterCount());
            for (int i = 0; i < method.getParameterCount(); i++) {
                System.out.println("入参-" + (i + 1) + "：类型：" + method.getParameterTypes()[i].getTypeName() + " 内容：" + args[i]);
            }
            System.out.println("出参类型：" + method.getReturnType().getName());
            System.out.println("出参结果：" + resObj);
            System.out.println("方法耗时：" + (System.currentTimeMillis() - start) + "ms");
        }
    }

}
